/**************************************************************************************************
* Title: RenderManager.cpp
* Authors: Gael Huber, Erin Mooney
* Description: Manages OpenGL rendering pipeline.
**************************************************************************************************/
#include "SmurfsRenderManager.h"

// Singleton instance
template<> RenderManager* Singleton<RenderManager>::singleton = 0;

/**************************************************************************************************
* Constructor
**************************************************************************************************/
RenderManager::RenderManager(void) {
	// Do nothing
}

/**************************************************************************************************
* Destructor
**************************************************************************************************/
RenderManager::~RenderManager(void) {
	// Do nothing
}

/**************************************************************************************************
* Initialize OpenGL
**************************************************************************************************/
void RenderManager::startUp(void) {
	// Initialize a new window
	_window = new Window();
	_window->startUp(L"SMURFS Engine", 640, 480, 16);

	glShadeModel(GL_SMOOTH);	// Enables smooth shading
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);	// Set a black background
	glClearDepth(1.0f);		// Depth buffer setup
	glEnable(GL_DEPTH_TEST);	// Enable depth testing
	glDepthFunc(GL_LEQUAL);	// The type of depth test
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);			// Really Nice Perspective Calculations

	// build a quadratic for the sphere
	quadratic=gluNewQuadric();			// Create A Pointer To The Quadric Object
	gluQuadricNormals(quadratic, GLU_SMOOTH);	// Create Smooth Normals
	gluQuadricTexture(quadratic, GL_TRUE);		// Create Texture Coords

	// Build the display lists
	//buildDisplayLists();

	// Build the font
	//buildFont();
}

/**************************************************************************************************
* Shutdown
**************************************************************************************************/
void RenderManager::shutDown(void) {
	killFont();	// Destroy the font used for text rendering

	gluDeleteQuadric(quadratic);	// Delete Quadratic - Free Resources

	// Destroy the window
	_window->shutDown();
	delete _window;
}

/**************************************************************************************************
* Get the singleton instance
**************************************************************************************************/
RenderManager& RenderManager::getSingleton(void) { 
	assert(singleton);
	return *singleton;
}

/**************************************************************************************************
* Get the singleton pointer
**************************************************************************************************/
RenderManager* RenderManager::getSingletonPtr(void) {
	return singleton;
}

/**************************************************************************************************
* Render the scene
**************************************************************************************************/
void RenderManager::renderScene(void) {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear the screen

	/*// translate and rotate the pyramid
	glLoadIdentity();
	glTranslatef(-1.5f,0.0f,-6.0f);				// Move Left And Into The Screen
	//glRotatef(rtri,0.0f,1.0f,1.0f);				// Rotate The Pyramid On It's Y Axis

	// pyramid
	glBegin(GL_TRIANGLES);					// Start Drawing The Pyramid
		glColor3f(1.0f,0.0f,0.0f);			// Red
		glVertex3f( 0.0f, 0.25f, 0.0f);			// Top Of Triangle (Front)
		glColor3f(0.0f,1.0f,0.0f);			// Green
		glVertex3f(-0.25f,-0.25f, 0.25f);			// Left Of Triangle (Front)
		glColor3f(0.0f,0.0f,1.0f);			// Blue
		glVertex3f( 0.25f,-0.25f, 0.25f);			// Right Of Triangle (Front)

		glColor3f(1.0f,0.0f,0.0f);			// Red
		glVertex3f( 0.0f, 0.25f, 0.0f);			// Top Of Triangle (Right)
		glColor3f(0.0f,0.0f,1.0f);			// Blue
		glVertex3f( 0.25f,-0.25f, 0.25f);			// Left Of Triangle (Right)
		glColor3f(0.0f,1.0f,0.0f);			// Green
		glVertex3f( 0.25f,-0.25f, -0.25f);			// Right Of Triangle (Right)

		glColor3f(1.0f,0.0f,0.0f);			// Red
		glVertex3f( 0.0f, 0.25f, 0.0f);			// Top Of Triangle (Back)
		glColor3f(0.0f,1.0f,0.0f);			// Green
		glVertex3f( 0.25f,-0.25f, -0.25f);			// Left Of Triangle (Back)
		glColor3f(0.0f,0.0f,1.0f);			// Blue
		glVertex3f(-0.25f,-0.25f, -0.25f);			// Right Of Triangle (Back)

		glColor3f(1.0f,0.0f,0.0f);			// Red
		glVertex3f( 0.0f, 0.25f, 0.0f);			// Top Of Triangle (Left)
		glColor3f(0.0f,0.0f,1.0f);			// Blue
		glVertex3f(-0.25f,-0.25f,-0.25f);			// Left Of Triangle (Left)
		glColor3f(0.0f,1.0f,0.0f);			// Green
		glVertex3f(-0.25f,-0.25f, 0.25f);			// Right Of Triangle (Left)
	glEnd();						// Done Drawing The Pyramid*/
	
	// Draw to the screen
	std::vector<Mesh*>::iterator start = drawList.begin();
	std::vector<Mesh*>::iterator end = drawList.end();
	for(std::vector<Mesh*>::iterator itr = start; itr != end; ++itr) {
		// Position The Cubes On The Screen
		glLoadIdentity();
		//glTranslatef(-1.5f,0.0f,-6.0f);
		//glTranslatef(-1.5f,0.0f,-6.0f);	
		glTranslatef((GLfloat) (*itr)->screenCoords.x, (*itr)->screenCoords.y, (*itr)->screenCoords.z);

		/*if((*itr)->type == SPHERE) {
			glColor3f(0.2f, 0.2f, 0.2f);
			gluSphere(quadratic,0.25f,32,32);
			
		} else {*/
			if((*itr)->type == PYRAMID || (*itr)->type == SPHERE)
				glBegin(GL_TRIANGLES);
			else
				glBegin(GL_QUADS);

			// Draw the mesh
			for(int i = 0; i < (*itr)->vertices.size(); i++) {
				Vector3 color = (*itr)->colors[i];
				Vector3 position = (*itr)->vertices[i];
				glColor3f(color.x, color.y, color.z);
				glVertex3f(position.x, position.y, position.z);
			}
		//}

		glEnd();
	}

	SwapBuffers(_window->getHDC());
}

/**************************************************************************************************
* Add an object to the scene
**************************************************************************************************/
void RenderManager::addToScene(Mesh* obj) {
	drawList.push_back(obj);
}

/**************************************************************************************************
* Remove an object from the scene
**************************************************************************************************/
void RenderManager::removeFromScene(GLuint id) {
}

/**************************************************************************************************
* Build a bitmap font
**************************************************************************************************/
void RenderManager::buildFont(void) {
	HFONT font;		// windows font
	HFONT oldfont;	// for "good housekeeping"

	base = glGenLists(96);

	// create the font based on the character height, not the cell height
	font = CreateFont(-24, 0, 0, 0, FW_BOLD, false, false, false, ANSI_CHARSET, OUT_TT_PRECIS, 
		CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_DONTCARE|DEFAULT_PITCH, (LPCWSTR)"Courier New");

	// set the new font by replacing the old
	oldfont = (HFONT)SelectObject(_window->getHDC(), font);
	wglUseFontBitmaps(_window->getHDC(), 32, 96, base);
	SelectObject(_window->getHDC(), oldfont);
	DeleteObject(font);
}

/**************************************************************************************************
* Destroy the font
**************************************************************************************************/
void RenderManager::killFont(void) {
	glDeleteLists(base, 96);		// delete all 96 characters
}

/**************************************************************************************************
* Prints whatever comes into the method
**************************************************************************************************/
void RenderManager::print(const char* toPrint) {
	char text[256];		// holds the string to be printed
	va_list ap;			// pointer to a list of arguments

	if(toPrint == NULL) return;		// there's nothing to print

	// check to see if there are any symbols that need to be converted and convert them
	va_start(ap, toPrint);
		vsprintf(text, toPrint, ap);
	va_end(ap);

	glPushAttrib(GL_LIST_BIT);		// prevents from affecting other display lists
	glListBase(base - 32);			// sets the base character to 32

	glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);	// draws the display list text
	glPopAttrib();	// pops the bits of the display list
}

/**************************************************************************************************
* Aligns and prints out the score
**************************************************************************************************/
void RenderManager::createScoreToPrint(int player, int ai) {
	// create the string to print
	char pScore[80]; char aScore[80];
	itoa(player, pScore, 10);
	itoa(ai, aScore, 10);
	strcpy(scoreString, pScore);
	strcat(scoreString, "     ");
	strcat(scoreString, aScore);
}

/**************************************************************************************************
* Returns the quadratic
**************************************************************************************************/
GLUquadricObj* RenderManager::getQuadratic(void) {
	return quadratic;
}